#define _WINSOCKAPI_ //Keeps windows from re-including Winsock
#include <d3dx9.h>

#include "InputMgr.h"
#include "Log.h"
#include "Network.h"
#include "World.h"

//TRAV:: Just including these to test them in main
#include "DirectXStuff.h"
#include "Player.h"
#include "MatrixStack.h"

#include <Windows.h>
#include <WindowsX.h>
#include <mmsystem.h>

#include <strsafe.h>

#pragma warning( disable : 4996 ) // disable deprecated warning

//Forward Declarations
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

void Start2()
{
	std::cout << "Incorrect input... \nType 's' to run as server\nType 'c' to run as client\n\n:>";
	char in;
	std::string ip;

	std::cin >> in;
	if(in == 's')
	{
		Network::Get()->Initalise(true);
	}
	if(in == 'c') {
		std::cout << "Enter the IP you wish to connect to\n:>";
		std::cin >> ip;
		Network::Get()->Initalise(false);
		Network::Get()->ConnectTo(ip, 50100); // 127.0.0.1 is your local IP
	} else if (in != 'c' && in != 's')
	{
		Start2();
	}	
}
void Start()
{
	//Ask whether we are a client or a server
	std::cout << "                   ------------------------------------------\n\n                   RSFPSA: Revolutionary Stagnation FPS Arena\n\n                   ------------------------------------------\n                             WELCOME TO THE LOBBY\n\nType 's' to run as server\nType 'c' to run as client\n\n:>";
	char in;
	std::string ip;

	std::cin >> in;
	if(in == 's')
	{
		Network::Get()->Initalise(true);
	}
	if(in == 'c') {
		std::cout << "Enter the IP you wish to connect to\n:>";
		std::cin >> ip;
		Network::Get()->Initalise(false);
		Network::Get()->ConnectTo(ip, 50100); // 127.0.0.1 is your local IP
	} else if (in != 'c' && in != 's') {
		std::cout << "Incorrect keystroke detected\n";
		Start2();
	}	
}

bool gameLoop = true;
bool lockMouse = false;

// MAIN FUNCTION
int main()
{
	//Register a window class
	Log("Initalising DirectX");
	WNDCLASSEX wc = 
	{
		sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,
        GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
        "window", NULL
    };	
	RegisterClassEx(&wc);

	

	//Create Window
	HWND hWnd = CreateWindow("window", "Revolutionarily Stagnated First Person Shooter Arena",
							 WS_OVERLAPPEDWINDOW , 300, 0, 1280, 720,
                             NULL, NULL, wc.hInstance, NULL );

	// Initialize Direct3D
    if( SUCCEEDED( InitD3D( hWnd ) ) )
	{
		UpdateWindow( hWnd );
		ShowWindow(hWnd, SW_SHOWDEFAULT);
		
		Log("DirectX initalised");
	}

	//Hide Mouse
	//ShowCursor(false);

	//Create the Network
	Network::Create();
	
	Start();

	//Create The World
	InputMgr::Create();
	World::Create();
	MatrixStack::Create();

	SetUpMatracies();

	//TRAVIS::For testing players 
	//Create 2 PlayerObjects then create a player controler that contols one of them 
	//Use:  AddEntity( ReferenceNumber, new Player() );


	//Set DirectX components (textures and whatnot)
	//Create Mesh 
	//Create Temporary mesh to give the GameObject
	
	//Create Entity from mesh 
	//Mesh* tempMesh = new Mesh(g_pd3dDevice, "Cube.x");
	//int Reference = 8;
	//World::Get().AddEntity( Reference, new Player(Reference, tempMesh, false) );
	//Player* TempPlayer = new Player(7, tempMesh);
	//TempPlayer->setPosition(0.0f, 0.0f, 0.0f);

	//Main Loop
	float lastTime, currentTime, deltaT;
	lastTime = (float)timeGetTime();
	MSG msg;
	ZeroMemory( &msg, sizeof( msg ) );

	while( msg.message != WM_QUIT || gameLoop)
	{
		if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		} else {

			//Get time since last tick
			currentTime = (float)timeGetTime();
			deltaT = (currentTime - lastTime);
			deltaT /= 1000.f;
			lastTime = currentTime;

			//If a server, update the current tick
			if( Network::Get()->IsServer() )
			{
				Network::Get()->UpdateTick(deltaT);
			}

			Network::Get()->PreUpdate();
			World::Get().Update(deltaT);
			Network::Get()->PostUpdate();
			Render();

			//Clear Input
			InputMgr::Get()->ClearMouseMovement();

			//Put cursor in the centre of the screen
			RECT rect;
			GetWindowRect(hWnd, &rect);
			if(lockMouse)
			{
				SetCursorPos(((rect.right - rect.left) / 2) + rect.left, ((rect.top - rect.bottom) / 2) + rect.bottom);
			}


		}
	}

	Log("Exiting...");

	Network::Delete();
	InputMgr::Delete();
	World::Delete();

	return 0;
} 

// CONTROLS
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{	
	float a, b;
	RECT rect;

	switch( msg )
	{
	case WM_DESTROY:
		PostQuitMessage( 0 );
		gameLoop = false;
		return 0;
		break;

	case WM_MOUSEMOVE:
		//Rotate the camera
		GetWindowRect(hWnd, &rect);
		a = LOWORD(lParam);
		b = HIWORD(lParam);
		
		a -= ( (rect.right - rect.left) / 2);
		b -= ( (rect.top - rect.bottom) / 2);
		InputMgr::Get()->SetMouseMovement((float)a, (float)b);
		break;

	case WM_KEYDOWN:
		if(wParam == 'W')
			InputMgr::Get()->SetKeyState(KEY_W, true);

		if(wParam == 'S') 
			InputMgr::Get()->SetKeyState(KEY_S, true);

		if(wParam == 'A')
			InputMgr::Get()->SetKeyState(KEY_A, true);
		
		if(wParam == 'D')
			InputMgr::Get()->SetKeyState(KEY_D, true);

		if(wParam == VK_SPACE)
		{
			
		}

		if(wParam == VK_ESCAPE)
		{
			if(lockMouse)
			{
				lockMouse = false;
			} else {
				lockMouse = true;
			}
		}
		break;

	case WM_LBUTTONDOWN:
		InputMgr::Get()->SetMouseDown(true);
		break;

	case WM_KEYUP:
		if(wParam == 'W')
			InputMgr::Get()->SetKeyState(KEY_W, false);

		if(wParam == 'S') 
			InputMgr::Get()->SetKeyState(KEY_S, false);

		if(wParam == 'A')
			InputMgr::Get()->SetKeyState(KEY_A, false);
		
		if(wParam == 'D')
			InputMgr::Get()->SetKeyState(KEY_D, false);
		break;
	}

	return DefWindowProc(hWnd, msg, wParam, lParam);
}